package cn.edu.lsu.integratedsurvey.tool;

import cn.edu.lsu.integratedsurvey.bean.LoginRecords;
import cn.edu.lsu.integratedsurvey.bean.User;
import cn.edu.lsu.integratedsurvey.config.JwtConfig;
import cn.edu.lsu.integratedsurvey.exception.SystemException;
import cn.edu.lsu.integratedsurvey.mapper.LoginRecordsMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * jwt工具类
 *
 * @author Jasmine-drs
 * @date 2024/5/2 10:26
 */

@Component
public class JwtUtil {

	private final JwtConfig jwtConfig;
	private final LoginRecordsMapper loginRecordsMapper;

	public JwtUtil(JwtConfig jwtConfig, LoginRecordsMapper loginRecordsMapper) {
		this.jwtConfig = jwtConfig;
		this.loginRecordsMapper = loginRecordsMapper;
	}

	/**
	 * 创建jwt
	 *
	 * @param user 用户对象
	 * @return jwt字符串
	 */
	public String createToken(User user) {
		Map<String, Object> claims = new HashMap<>();
		claims.put("id", user.getId());
		claims.put("name", user.getName());
		claims.put("account", user.getAccount());
		claims.put("role", user.getRole());
		claims.put("department", user.getDepartment());
		claims.put("operatorId", user.getOperatorId());
		claims.put("status", user.getStatus());
//		claims.put("createTime", user.getCreateTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
//		claims.put("updateTime", user.getUpdateTime().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
		String secretKey = jwtConfig.getSecretKey();
		long expirationTime = jwtConfig.getExpirationTime();
		return Jwts.builder()
				.setClaims(claims)
				.setIssuedAt(new Date(System.currentTimeMillis()))
				.setExpiration(new Date(System.currentTimeMillis() + expirationTime))
				.signWith(SignatureAlgorithm.HS256, secretKey)
				.compact();
	}

	/**
	 * 解析jwt
	 *
	 * @param token jwt字符串
	 * @return jwt的有效载荷
	 */
	public Map<String, Object> parseToken(String token) {
//		获取密钥
		String secretKey = jwtConfig.getSecretKey();
//		存储jwt的有效载荷
		Map<String, Object> response = new HashMap<>();
		try {
//			解析jwt
			Claims claims = Jwts.parser()
					.setSigningKey(secretKey)
					.parseClaimsJws(token)
					.getBody();
			response.put("status", "success");
			response.put("claims", claims);
		} catch (ExpiredJwtException e) {
			response.put("status", "error");
			response.put("message", "登录已过期，请重新登录");
//			删除登录记录
			loginRecordsMapper.delete(new QueryWrapper<LoginRecords>().eq("jwt", token));
			throw new SystemException("登录已过期，请重新登录", 501);
		} catch (UnsupportedJwtException e) {
			response.put("status", "error");
			response.put("message", "不支持的身份验证信息");
			throw new SystemException("不支持的身份验证信息", 502);
		} catch (MalformedJwtException e) {
			response.put("status", "error");
			response.put("message", "身份验证信息格式不正确");
			throw new SystemException("身份验证信息格式不正确", 503);
		} catch (SignatureException e) {
			response.put("status", "error");
			response.put("message", "身份验证信息无效");
			throw new SystemException("身份验证信息无效", 504);
		} catch (IllegalArgumentException e) {
			response.put("status", "error");
			response.put("message", "身份验证信息为null或为空");
			throw new SystemException("身份验证信息为null或为空", 505);
		} catch (JwtException e) {
			response.put("status", "error");
			response.put("message", "分析身份验证信息时出错，请联系服务器管理员");
			throw new SystemException("分析身份验证信息时出错，请联系服务器管理员", 506);
		}
//		查找是否有登录记录
		List<LoginRecords> jwt = loginRecordsMapper.selectList(new QueryWrapper<LoginRecords>().eq("jwt", token));
//		没有登录记录则表示登录已过期或者jwt泄露，此时需要抛出异常拒绝访问
		if (jwt.size() == 0) {
			response.put("status", "error");
			response.put("message", "登录状态异常，请重新登录");
			throw new SystemException("登录状态异常，请重新登录", 507);
		}
		return response;
	}

	/**
	 * 判断是否是普通管理员
	 *
	 * @param token jwt字符串
	 * @return true是普通管理员，false不是普通管理员
	 */
	public boolean isAdmin(String token) {
		Map<String, Object> claims = parseToken(token);
		if (claims.get("status").equals("success")) {
			Claims claims1 = (Claims) claims.get("claims");
//			小于等于1目的是为了让超级管理员能通过
			return (int) claims1.get("role") <= 1;
		}
		return false;
	}

	/**
	 * 判断是否是超级管理员
	 *
	 * @param token jwt字符串
	 * @return true是超级管理员，false不是超级管理员
	 */
	public boolean isRoot(String token) {
		Map<String, Object> claims = parseToken(token);
		if (claims.get("status").equals("success")) {
			Claims claims1 = (Claims) claims.get("claims");
			return (int) claims1.get("role") == 0;
		}
		return false;
	}
}
